package us.nchu.onlineJudger.bean;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.http.HttpUtil;
import us.nchu.onlineJudger.util.Md5Util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;

public class CPlusJudger extends AbstractJudger{
    private MqMessage message = null;

    public CPlusJudger() {
    }

    public CPlusJudger(MqMessage message) {
        this.message = message;
    }

    public MqMessage getMessage() {
        return message;
    }

    public void setMessage(MqMessage message) {
        this.message = message;
    }

    @Override
    public CPlusResult doJudge() {
        String dataPath = props.getStr("judger.dataPath") + "/" + message.getDataPath();
        String curPath = props.getStr("judger.judgerPath");
        String runPath = props.getStr("judger.runPath");
        Integer maxDownloadTime = Integer.parseInt(props.getStr("judger.downloadMaxTime"));
        File dataFile = new File(dataPath);

        // 如果不存在数据文件,则需要去配置文件里写明的地址下载
        if (!dataFile.exists()) {
            System.out.println("start download");
            boolean md5Correct = false;
            // 尝试多次下载
            for(int i = 0; i < maxDownloadTime; i++) {
                System.out.println("start download at url: " + props.getStr("judger.defaultDownloadUrl") + message.getDataPath() + ".zip");
                System.out.println("save at: " + props.getStr("judger.dataPath") + "/");
                long fileSize = HttpUtil.downloadFile(props.getStr("judger.defaultDownloadUrl") + message.getDataPath() + ".zip",
                        props.getStr("judger.dataPath") + "/");

                try {
                    System.out.println("start calc md5");
                    String md5 = Md5Util.fileToMd5(dataPath + ".zip");
                    System.out.println("md5 is: " + md5);

                    // 对比下载到的文件md5和要评测的md5值
                    if(md5.equals(message.getDataPath())) {
                        System.out.println("md5 correct");
                        // 跳出下载循环
                        md5Correct = true;
                        break;
                    }
                } catch (IOException e) {
                    // 这是Md5Util类抛出的异常,是说找不到要计算md5的文件
                    // 但实际上如果HttpUtil下载失败了,会创建一个空的文件(大小为0kb的测试zip文件)
                    // 所以这个catch实际上是不存在的
                    if (e instanceof FileNotFoundException) {
                        e.printStackTrace();
                    }
                }
            }

            // 如果走到这一步,md5还是不匹配的,说明下载文件失败,直接返回错误
            if(!md5Correct) {
                // 停止此次检测,直接返回10,SYSTEM_ERROR,0,0
                // 返回值为10代表找不到测试数据

                // 先删除下载的数据
                FileUtil.del(dataPath + ".zip");
                // 再删除解压失败的目录
                FileUtil.del(dataPath);
                System.out.println("directly return");
                // 直接结束
                return new CPlusResult(10, "SYSTEM_ERROR", 0, 0, null);
            }

            System.out.println("start unzip");
            // 开始解压下载的文件
            ZipUtil.unzip(props.getStr("judger.dataPath") + "/" + message.getDataPath() + ".zip",
                    dataPath);
            System.out.println("finish unzip");
        }


        // 将代码写入到judger的运行目录中
        FileWriter fileWriter = new FileWriter(curPath + "/a.cpp");
        fileWriter.write(message.getCode());

        // 开始评测
        StringBuilder execString = new StringBuilder();
        // 构造执行语句
        execString.append(curPath).append("/judger")
                .append(" -c ").append(curPath).append("/a.cpp")
                .append(" -p ").append(curPath)
                .append(" -r ").append(runPath)
                .append(" -d ").append(dataPath);
        System.out.println("exec: " + execString.toString());
        try {
            // 开始执行
            Runtime runtime = Runtime.getRuntime();
            Process process = runtime.exec(execString.toString());

            // 等待执行结束
            if(0 != process.waitFor()) {
                if(0 != process.exitValue())
                    System.out.println("程序非正常结束");
            }

            int code = 0;
            String out = null;
            int timelimit = 0, memorylimit = 0;

            // 读结果
            Scanner scanner = new Scanner(new File(runPath + "/result.txt"));
            code = scanner.nextInt(); scanner.nextLine();
            out = scanner.nextLine();
            timelimit = scanner.nextInt(); scanner.nextLine();
            memorylimit = scanner.nextInt(); scanner.nextLine();
            StringBuilder msgBuilder = new StringBuilder();
            while(scanner.hasNext()) {
                msgBuilder.append(scanner.nextLine());
                msgBuilder.append("\n");
            }

            // 如果报错信息不为空,就把报错信息中关于路径的值替换掉
            String msg = null;
            if(!msgBuilder.toString().equals("")) {
                msg = msgBuilder.toString();
                msg = msg.replaceAll(curPath, "");
                msg = msg.replaceAll("\n", "<br>");
                msg = msg.replaceAll(" ", "&nbsp;");
                msg = HtmlUtil.escape(msg);
            }

            // 输出结果
            System.out.println("code = " + code);
            System.out.println("final is " + out);
            System.out.println("timecost = " + timelimit);
            System.out.println("memorycost = " + memorylimit);
            System.out.println("msg = " + msg);

            // 删除生成的文件
            FileUtil.del(curPath + "/a.cpp");
            FileUtil.del(runPath + "/result.txt");

            return new CPlusResult(code, out, timelimit, memorylimit, msg);

        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        return null;
    }
}
